package com.ruoyi.ora.netty.channel.handler;

import com.ruoyi.common.enums.dict.AudioCallStatus;
import com.ruoyi.common.enums.dict.AudioCallType;
import com.ruoyi.common.enums.dict.DeviceUserStatus;
import com.ruoyi.common.utils.ByteUtil;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.bean.Builder;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.ora.constant.BizConstants;
import com.ruoyi.ora.domain.Device;
import com.ruoyi.ora.domain.DeviceUser;
import com.ruoyi.ora.netty.channel.domain.CallEntity;
import com.ruoyi.ora.netty.channel.domain.ChannelHandlerBase;
import com.ruoyi.ora.service.IDeviceService;
import com.ruoyi.ora.service.IDeviceUserService;
import io.netty.channel.ChannelHandlerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

public class ForwardAudioHandler extends ChannelHandlerBase {

    private Logger logger = LoggerFactory.getLogger("ChannelTcpServerThread");

    private IDeviceUserService deviceUserService = SpringUtils.getBean(IDeviceUserService.class);
    private IDeviceService deviceService = SpringUtils.getBean(IDeviceService.class);

    private static int callId = 200;

    public ForwardAudioHandler(){

    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, byte[] bytes) throws Exception {
        try{

            logger.info("通道"+ctx.channel().id().asLongText()+"，接收数据包：" + ByteUtil.bytesToHex(bytes));

//            处理数据
            /**
             * bytes[2]  标识协议类型， 0x02：设备上传帧， 0x03：APP上传帧， 0x09：服务器发送帧
             * bytes[3]  帧类型， 0：心跳，1：呼叫，2：接通，3：音频流，8：挂断，
             */


            String userId = ByteUtil.bytesToHex(ByteUtil.subBytes(bytes, 20, 8));

            if (bytes[3] == 0x00){
                BizConstants.Channel.CHANNEL_USERID_MAP.put(userId, ctx.channel().id().asLongText());
//                BizConstants.Channel.CHANNEL_MAP.put(ctx.channel().id().asLongText(), ctx.channel());
//                if (bytes[2] == 0x02){
//                    // 设备
//                    BizConstants.Channel.CHANNEL_DEVICE_MAP.put(signId, ctx.channel());
//                }else if (bytes[2] == 0x03){
//                    // app
//                    BizConstants.Channel.CHANNEL_APP_MAP.put(signId, ctx.channel());
//                }
            } else if (bytes[3] == 0x01){
                BizConstants.Channel.CHANNEL_USERID_MAP.put(userId, ctx.channel().id().asLongText());
                /**
                 * 呼叫帧
                 */
                callHandle(ctx, bytes, userId);
            }else if (bytes[3] == 2){
                BizConstants.Channel.CHANNEL_USERID_MAP.put(userId, ctx.channel().id().asLongText());
                /**
                 * 接通帧
                 */
                connectionHandle(ctx, bytes, userId);
            }else if (bytes[3] == 3){
                /**
                 * 音频流帧 透传给不包含自己的所有人
                 */
                audioStreamHandle(ctx, bytes, userId);
            }else if (bytes[3] == 8){
                /**
                 * 挂断帧 透传给所有人
                 */
                hangupHandle(ctx, bytes, userId);
            }else {
                // 其他帧不做处理
            }

        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 呼叫处理
     * @param ctx
     * @param bytes
     * @param userId
     */
    public void callHandle(ChannelHandlerContext ctx, byte[] bytes, String userId){
        /**
         * 设备呼叫则获取设备下绑定的所有用户 生成通话id 发送呼叫帧  app点接听回复接听帧 透传给设备
         * App呼叫直接给设备发送呼叫帧  生成通话id  设备回复接听帧  透传给app
         * 呼叫帧建议5秒发送一次，如30秒无回复则认为呼叫失败
         */
        if (bytes[2] == 0x02){
            CallEntity callEntity = BizConstants.Channel.CHANNEL_CALL_MAP.get(ctx.channel().id().asLongText());
            // 判断是否已经存在通话
            if (callEntity == null){
                // 初始化 设备呼叫
                callEntity = new CallEntity();
                callEntity.setCallType(AudioCallType.DEVICE_TO_APP.getValue());
                callEntity.setUserId(userId);
                callEntity.setDeviceSn(userId);
                callEntity.setChannelId(ctx.channel().id().asLongText());
                callEntity.setCallStatus(AudioCallStatus.CALLING.getValue());
                callEntity.setCallTime(new Date());
                callEntity.setCallId(callId++);
                BizConstants.Channel.CHANNEL_CALL_MAP.put(ctx.channel().id().asLongText(), callEntity);
                callMapPut(callEntity.getCallId(), callEntity);
            }

            Device device = deviceService.selectOneDevice(Builder.of(Device::new)
                    .with(Device::setDeviceSn, String.valueOf(Long.parseLong(userId))).build());
            if (device != null){
                List<DeviceUser> deviceUsers = deviceUserService.selectDeviceUserList(Builder.of(DeviceUser::new)
                        .with(DeviceUser::setDeviceId, device.getId())
                        .with(DeviceUser::setStatus, DeviceUserStatus.BIND.getValue()).build());
                // 发送给绑定的用户
                for (DeviceUser deviceUser : deviceUsers) {
                    // 根据用户id获取通道id
                    String channelId = BizConstants.Channel.CHANNEL_USERID_MAP.get(ByteUtil.bytesToHex(ByteUtil.longToBytes(deviceUser.getUserId(), 8)));
                    if (channelId != null){
                        writeAndFlush(BizConstants.Channel.CHANNEL_MAP.get(channelId), ByteUtil.bytesReplace(bytes, 10, ByteUtil.intToBytes(callEntity.getCallId(), 2)));
                    }
                }
//                // TODO 发送给所有用户  按设备号过滤用户
//                for (String key : BizConstants.Channel.CHANNEL_MAP.keySet()) {
//                    writeAndFlush(BizConstants.Channel.CHANNEL_MAP.get(key), ByteUtil.bytesReplace(bytes, 10, ByteUtil.intToBytes(callEntity.getCallId(), 2)));
//                }
            }

        }
        if (bytes[2] == 0x03){
            CallEntity callEntity = BizConstants.Channel.CHANNEL_CALL_MAP.get(ctx.channel().id().asLongText());
            if (callEntity == null){
                // app呼叫
                callEntity = new CallEntity();
                callEntity.setCallType(AudioCallType.APP_TO_DEVICE.getValue());
                callEntity.setUserId(userId);
                callEntity.setChannelId(ctx.channel().id().asLongText());
                callEntity.setCallStatus(AudioCallStatus.CALLING.getValue());
                callEntity.setCallTime(new Date());
                callEntity.setCallId(callId++);
                BizConstants.Channel.CHANNEL_CALL_MAP.put(ctx.channel().id().asLongText(), callEntity);
                callMapPut(callEntity.getCallId(), callEntity);
            }

            // 获取设备id
            Long deviceId = ByteUtil.bytesToLong(ByteUtil.subBytes(bytes, 12, 2));

            Device device = deviceService.selectDeviceById(deviceId);
            if (device != null){
                // 根据用户id获取通道id
                String channelId = BizConstants.Channel.CHANNEL_USERID_MAP.get(StringUtils.leftPad(device.getDeviceSn(), 16, '0'));
                if (channelId != null){
                    writeAndFlush(BizConstants.Channel.CHANNEL_MAP.get(channelId), ByteUtil.bytesReplace(bytes, 10, ByteUtil.intToBytes(callEntity.getCallId(), 2)));
                }
            }

//            // TODO 发送给设备  根据用户获取到绑定的设备id
//            for (String key : BizConstants.Channel.CHANNEL_MAP.keySet()) {
//                writeAndFlush(BizConstants.Channel.CHANNEL_MAP.get(key), ByteUtil.bytesReplace(bytes, 10, ByteUtil.intToBytes(callEntity.getCallId(), 2)));
//            }

        }
    }

    /**
     * 连接处理
     * @param ctx
     * @param bytes
     */
    public void connectionHandle(ChannelHandlerContext ctx, byte[] bytes, String userId){
        int callId = ByteUtil.bytesToInt(ByteUtil.subBytes(bytes, 10, 2));

        List<CallEntity> callEntitys = BizConstants.Channel.CALL_MAP.get(callId);
        for (CallEntity callEntity : callEntitys) {
            callEntity.setCallStatus(AudioCallStatus.CONNECTED.getValue());
            // 接通透传给接听之前的所有用户
            writeAndFlush(BizConstants.Channel.CHANNEL_MAP.get(callEntity.getChannelId()), bytes);
            // 清除呼叫
            BizConstants.Channel.CHANNEL_CALL_MAP.remove(callEntity.getChannelId());
        }

        // 新的接通对象
        CallEntity callEntity = new CallEntity();
        callEntity.setUserId(userId);
        callEntity.setChannelId(ctx.channel().id().asLongText());
        callEntity.setCallStatus(AudioCallStatus.CONNECTED.getValue());
        callEntity.setConnectTime(new Date());
        callEntity.setCallId(callId);
        if (bytes[2] == 0x02){
            // 设备接听
            callEntity.setCallType(AudioCallType.DEVICE_ANSWER.getValue());
        }else if (bytes[2] == 0x03){
            // app接听
            callEntity.setCallType(AudioCallType.APP_ANSWER.getValue());
        }

        callMapPut(callEntity.getCallId(), callEntity);
    }

    /**
     * 音频流处理
     * @param ctx
     * @param bytes
     * @param userId
     */
    public void audioStreamHandle(ChannelHandlerContext ctx, byte[] bytes, String userId){
        // 透传给不包含自己的所有人
        int callId = ByteUtil.bytesToInt(ByteUtil.subBytes(bytes, 10, 2));
        List<CallEntity> callEntitys = BizConstants.Channel.CALL_MAP.get(callId);
        for (CallEntity callEntity : callEntitys) {
            if (!callEntity.getUserId().equals(userId)){
                writeAndFlush(BizConstants.Channel.CHANNEL_MAP.get(callEntity.getChannelId()), bytes);
            }
        }
    }

    /**
     * 挂断处理
     * @param ctx
     * @param bytes
     * @param userId
     */
    public void hangupHandle(ChannelHandlerContext ctx, byte[] bytes, String userId){
        int callId = ByteUtil.bytesToInt(ByteUtil.subBytes(bytes, 10, 2));
        List<CallEntity> callEntities = BizConstants.Channel.CALL_MAP.get(callId);

        // 移除原用户id添加新的
        Iterator<CallEntity> iterator = callEntities.iterator();
        while (iterator.hasNext()){
            CallEntity next = iterator.next();
            if (next.getUserId().equals(userId)){
//                next.setCallStatus(AudioCallStatus.DISCONNECTED.getValue());
//                next.setEndTime(new Date());
//                next.setCallDuration((int) ((next.getEndTime().getTime() - next.getConnectTime().getTime()) / 1000));
                // TODO 后面如果有记录操作可以存库 这里暂时不处理
                iterator.remove();
            }else {
                writeAndFlush(BizConstants.Channel.CHANNEL_MAP.get(next.getChannelId()), bytes);
            }
        }
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {

        System.out.println("丢失心跳：" + ctx.channel().id());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext channelHandlerContext, Throwable cause){
        cause.printStackTrace();
        channelHandlerContext.close();
    }

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) {
        System.out.println("通道注册：" + ctx.channel().id());
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        BizConstants.Channel.CHANNEL_MAP.put(ctx.channel().id().asLongText(), ctx.channel());
        System.out.println("通道连接：" + ctx.channel().id());
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        BizConstants.Channel.CHANNEL_MAP.remove(ctx.channel().id().asLongText());
        System.out.println("通道断开：" + ctx.channel().id());
        ctx.close();
    }

    public void callMapPut(Integer callId, CallEntity callEntity){
        List<CallEntity> callEntities = BizConstants.Channel.CALL_MAP.get(callId);
        if (callEntities == null){
            callEntities = new ArrayList<>();
            BizConstants.Channel.CALL_MAP.put(callEntity.getCallId(), callEntities);
        }
        // 移除原用户id添加新的
        Iterator<CallEntity> iterator = callEntities.iterator();
        while (iterator.hasNext()){
            CallEntity next = iterator.next();
            if (next.getUserId().equals(callEntity.getUserId())){
                iterator.remove();
            }
        }
        callEntities.add(callEntity);
    }

    public static void main(String[] args) {
        String deviceSn = "867417050321130";
//
//        Long id = ByteUtil.bytesToLong(ByteUtil.hexToBytes(deviceSn));
//
//        System.out.println(id);
//        System.out.println(String.valueOf(Long.parseLong(deviceSn)));

        System.out.println(StringUtils.leftPad(deviceSn, 16, '0'));
    }

}
